package com.tcm.smarthealth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tcm.smarthealth.document.ImageRecord;
import com.tcm.smarthealth.dto.HistoryItemResponse;
import com.tcm.smarthealth.dto.HistoryResponse;
import com.tcm.smarthealth.dto.HistoryStatsResponse;
import com.tcm.smarthealth.entity.Question;
import com.tcm.smarthealth.enums.HistoryItemType;
import com.tcm.smarthealth.enums.ImageAnalysisType;
import com.tcm.smarthealth.enums.QuestionType;
import com.tcm.smarthealth.service.HistoryService;
import com.tcm.smarthealth.service.QuestionService;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service
public class HistoryServiceImpl implements HistoryService {

    private static final int MAX_FETCH_LIMIT = 100;

    private final QuestionService questionService;
    private final MongoTemplate mongoTemplate;

    public HistoryServiceImpl(QuestionService questionService, MongoTemplate mongoTemplate) {
        this.questionService = questionService;
        this.mongoTemplate = mongoTemplate;
    }

    @Override
    public HistoryResponse fetchHistory(Long userId, HistoryItemType type, int page, int size) {
        int safePage = Math.max(page, 1);
        int safeSize = size > 0 ? size : 10;
        int fetchLimit = Math.min(MAX_FETCH_LIMIT, safeSize * safePage + 20);

        List<HistoryItemResponse> combined = new ArrayList<>();

        // Question records from MySQL
        List<Question> questionRecords = new ArrayList<>();
        long totalQuestions = 0;
        LocalDateTime latestQuestionTime = null;

        if (type == null || type == HistoryItemType.QUESTION) {
            LambdaQueryWrapper<Question> wrapper = new LambdaQueryWrapper<Question>()
                    .eq(Question::getUserId, userId)
                    .orderByDesc(Question::getCreatedAt)
                    .last("LIMIT " + fetchLimit);
            questionRecords = questionService.list(wrapper);

            totalQuestions = questionService.lambdaQuery()
                    .eq(Question::getUserId, userId)
                    .count();

            Question latestQuestion = questionService.lambdaQuery()
                    .eq(Question::getUserId, userId)
                    .orderByDesc(Question::getCreatedAt)
                    .last("LIMIT 1")
                    .one();
            latestQuestionTime = latestQuestion != null ? latestQuestion.getCreatedAt() : null;

            for (Question question : questionRecords) {
                combined.add(convertQuestionRecord(question));
            }
        }

        // Image records from MongoDB
        List<ImageRecord> imageRecords = new ArrayList<>();
        long totalImages = 0;
        LocalDateTime latestImageTime = null;

        if (type == null || type == HistoryItemType.IMAGE) {
            Query baseQuery = Query.query(Criteria.where("user_id").is(userId));
            totalImages = mongoTemplate.count(baseQuery, ImageRecord.class);

            Query latestQuery = baseQuery.with(Sort.by(Sort.Direction.DESC, "created_at")).limit(1);
            ImageRecord latest = mongoTemplate.findOne(latestQuery, ImageRecord.class);
            latestImageTime = latest != null ? latest.getCreatedAt() : null;

            Query listQuery = Query.query(Criteria.where("user_id").is(userId));
            if (type == HistoryItemType.IMAGE) {
                listQuery.addCriteria(Criteria.where("analysis_type").exists(true));
            }
            listQuery.with(Sort.by(Sort.Direction.DESC, "created_at")).limit(fetchLimit);
            imageRecords = mongoTemplate.find(listQuery, ImageRecord.class);

            for (ImageRecord imageRecord : imageRecords) {
                combined.add(convertImageRecord(imageRecord));
            }
        }

        combined.sort(Comparator.comparing(HistoryItemResponse::getTimestamp, Comparator.nullsLast(LocalDateTime::compareTo)).reversed());

        int fromIndex = Math.min((safePage - 1) * safeSize, combined.size());
        int toIndex = Math.min(fromIndex + safeSize, combined.size());
        List<HistoryItemResponse> pageItems = combined.subList(fromIndex, toIndex);

        HistoryStatsResponse stats = new HistoryStatsResponse();
        stats.setTotalQuestionRecords(totalQuestions);
        stats.setTotalImageRecords(totalImages);
        stats.setLatestQuestionTime(latestQuestionTime);
        stats.setLatestImageTime(latestImageTime);

        HistoryResponse response = new HistoryResponse();
        response.setStats(stats);
        response.setItems(pageItems);
        return response;
    }

    private HistoryItemResponse convertQuestionRecord(Question question) {
        HistoryItemResponse item = new HistoryItemResponse();
        item.setId(String.valueOf(question.getId()));
        item.setType(HistoryItemType.QUESTION.name());

        String questionContent = Optional.ofNullable(question.getQuestion()).orElse("未填写问题内容");
        item.setTitle(truncate(questionContent, 40));
        item.setSummary(Optional.ofNullable(question.getAnswer()).orElse("暂无回答"));
        item.setTimestamp(question.getCreatedAt());

        List<String> tags = new ArrayList<>();
        tags.add("问答记录");
        QuestionType questionType = resolveQuestionType(question.getQaType());
        if (questionType != null) {
            tags.add(questionType.getDisplayName());
        }
        item.setTags(tags);

        Map<String, Object> metadata = new HashMap<>();
        metadata.put("qaType", question.getQaType());
        metadata.put("confidence", question.getConfidence() != null ? question.getConfidence() : BigDecimal.ZERO);
        metadata.put("answer", Optional.ofNullable(question.getAnswer()).orElse(""));
        item.setMetadata(metadata);

        return item;
    }

    private HistoryItemResponse convertImageRecord(ImageRecord record) {
        HistoryItemResponse item = new HistoryItemResponse();
        item.setId(record.getId());
        item.setType(HistoryItemType.IMAGE.name());

        ImageAnalysisType analysisType = resolveAnalysisType(record.getAnalysisType());
        String display = analysisType != null ? analysisType.getDisplayName() : "影像分析";
        item.setTitle(display + " · " + Optional.ofNullable(record.getFilename()).orElse("未命名图片"));
        item.setSummary(record.getDiagnosis());
        item.setTimestamp(record.getCreatedAt());

        List<String> tags = new ArrayList<>();
        tags.add("影像分析");
        if (analysisType != null) {
            tags.add(analysisType.getDisplayName());
        }
        item.setTags(tags);

        Map<String, Object> metadata = new HashMap<>();
        metadata.put("analysisType", record.getAnalysisType());
        metadata.put("confidence", record.getConfidence() != null ? record.getConfidence() : BigDecimal.ZERO);
        metadata.put("suggestions", record.getSuggestions());
        metadata.put("previewUrl", "/v1/images/" + record.getId() + "/preview");
        item.setMetadata(metadata);

        return item;
    }

    private QuestionType resolveQuestionType(String code) {
        if (code == null) {
            return null;
        }
        try {
            return QuestionType.fromCode(code);
        } catch (Exception ex) {
            return null;
        }
    }

    private ImageAnalysisType resolveAnalysisType(String code) {
        if (code == null) {
            return null;
        }
        try {
            return ImageAnalysisType.fromCode(code);
        } catch (Exception ex) {
            return null;
        }
    }

    private String truncate(String value, int length) {
        if (value == null || value.length() <= length) {
            return value;
        }
        return value.substring(0, length) + "...";
    }
}

